Vicimus GEGAN By Alex Young Contents 1. Introduction 2. Algorithms 2.1 Rain and wind sounds 2.2 rndtxt 6 2.3 rndtxt 7 2.4 rndtxt 8 2.5 rndtxt 3. Performance 4. Composition 5. Cover art 6. Licensing A1. Appendix 1: Sample Python cSound Script A2. Appendix 2: Script to generate a wall of spam 1. Introduction The RNDTXT Microsound project presents us with potentially limitless creative opportunities: with a large enough data set it is possible to create anything you want. However, I find the sense of irony in taking data which derived from a source of so much frustration and then creating something interesting too tempting to pass up. Therefore, during this project I attempted to keep in mind these goals: 1. To see how non-random interpretations of the data could lead to distinct patterns; 2. To imprint a human influence onto the interpreted data set; 3. To continue my efforts to understand how to manipulate and control microseconds of audio to create synthesized sounds. 2. Algorithms I wrote a Python script to generate cSound score files. My initial idea was to create score files with potentially thousands of lines of very short notes to build up a complex and interesting sound, using scripts generally based on the structure shown in the Appendix [A1]. I found it simple enough to create white noise from the text file, but algorithms that created other kinds sounds was more challenging. The cSound generator's partials were found by adding up the distribution of letters found in the file. This produced the familiar bell curve of the normal distribution. I divided each value for each letter by 1000 to calculate the values for the partials. 2.1 Rain and wind sounds The first set of python scripts I wrote produced notes that lasted around 0.05 seconds at regular intervals. I didn't attempt to sort the data and interpreted it as is in the original file. By adding up the ordinal value of each letter in a word I determined the pitch of the note, and the length of the word determined the length of the note. If I slowed the tempo of the cSound file strange melodies could be found within the noise, which seem to exhibit self similarity. If I was a better mathematician I might be able to calculate the fractal dimension of the original data set, or use other tools like the chaos game [1] to explore the patterns within it. What I discovered from the granular white noise I made was if I 'played' a graphic equalizer while auditioning it I could create the effects of thunder. By using smaller grains, and by playing a 12db low pass filter, I created a sound like wind. 2.2 rndtxt 6 This algorithm created low frequency sounds which I used to produce the bass drum. This was the first algorithm where I ordered the word values and lengths. To add variation to the sound I experimented with using modulus and sin() (effectively producing an LFO), but simply ordering arrays of the word values/lengths was more interesting. To create the values for the score file, I did this: note = float(word_value) / float(longest_word) length = float(word_length) / (float(word_value % longest) + 1.0) * granularity var_granularity = granularity / (word_value + 1) attack = var_granularity / length score_entry = I(1, time, round(length + var_granularity, 6), note, amplitude, round(attack, 6)) stdout.write(ScoreSection(score_entry)) time += length Since the time is being incremented by the length of the notes, var_granularity was used to add variation to this. 2.3 rndtxt 7 This algorithm was used to produce the sporadic synth sound and high frequency percussive sounds which are introduced during the last 1/4 of the piece. The algorithm this time is a variation on the previous one where I changed the tempo of the cSound file and the granularity. 2.4 rndtxt 8 This algorithm was used for creating the closed hi hat sound and the flute sound. To do this, the script adds up the ASCII value of each word and stores this in an array with its word length. Then it goes through each word and length, and takes these as coordinates on the complex plane. Euler's zeta product [2] is then calculated up to a specified number of iterations. The values produced are then interpreted as grains of a granulated sound: 1. Get the word values and word lengths 2. Let word_value = a and word_length = b Let z = z + (1 / (a + bi ^ s)) 3. Take time = a * granularity note length = (z.real - a) * z.imag * granularity pitch = z.real amplitude = z.imag + floor I tried swapping around the values to create different effects. I would have liked to extend this to use multiple cSound instruments. I realised afterwards this would have been much more interesting if I'd used Riemann's Zeta function [3] in a similar way to the method used to produce the graphs in [3] (and commonly found in textbooks), but all I wanted to do was create sounds by throwing grains of sound over the complex plane. In retrospect this is one area I could have researched more, which would have helped improve my knowledge of mathematics at least. The flute sound was made by pitch shifting the output of cSound. I found if I selected small parts of the sound with the mouse in DSP Quattro and then extended the range, it produced interesting variations on the sound when it was set to loop. I recorded myself doing this with AudioHijack, and then edited the results in the same package. 2.5 rndtxt I produced audio files directly from the text file by using sox: cat rndtxt.txt | sox -c 2 -r 48000 -b -u -t raw - test.wav This resulted in the snare sound after some chopping and EQing. 3. Performance I didn't just attempt to process the file with cSound and Python, I also use a speech synthesizer called FreeTTS [4] and Bidule [5]. The program in the binary distribution of FreeTTS allows you to easily produce sounds from a text file. I took these sounds and built a modular synth in Bidule, which has a simple granular sampler. Programming my keyboard's various knobs and sliders to control the granular sample playback units and effects in Bidule was surprisingly effective. 4. Composition I sequenced the samples I had created in a similar way to some other projects I've been doing recently ('The Montage Studies' [6]). 5. Cover art See Appendix A2 for my humorous script to generate a giant billboard of spam, from spam. 6. Licensing I place all of the sounds derived for this composition and Vicimus GEGAN itself in the Public Domain. A1. Appendix 1: Sample Python cSound Script #### Example Python script #!/usr/bin/env python from omde.csound import I, ScoreSection, stdout filename = '../text/rndtxt.txt' granularity = 0.001 tempo = 90 attack = 0.05 time = 0 # open the file text_file = open(filename) lines = text_file.read().split('\n') print """ f1 0 1024 10 0.17377 0.00060 0.00064 0.00067 0.00071 0.12002 0.03529 0.06787 0.04702 0.14083 0.02099 0.03191 0.03658 0.09852 0.00252 0.01203 0.06980 0.03879 0.08536 0.09009 0.03336 0.00234 0.09169 0.05883 0.07823 0.04301 0.01063 0.00778 0.00502 0.02441 0.00256 t 0 %d """ % (tempo) for line in lines: for word in line.split(' '): word_value = 0 for letter in word: word_value += ord(letter) # At this point I either added the word lengths and added ascii values to an array to be sorted and then processed, or created cSound score instructions straight away, like this: var_granularity = float(word_value) / float(len(word) + 1) / granularity length = abs(float(len(word) + 1) / granularity) note = (word_value / 6) + 100 attack = float(len(word)) / (note + 800) + 0.001 score_entry = I(1, time, round(length + var_granularity, 6), note, amplitude, round(attack, 6)) stdout.write(ScoreSection(score_entry)) time += length # # # End A2. Appendix 2: Script to generate a wall of spam Note: I produced the spam_cropped file from the SPAM logo (of the tinned food), by doing this: # Convert PNG to PBM and scale convert spam_cropped.png -scale 150 spam_cropped_small.pbm # Convert to text pbmtoascii spam_cropped_small.pbm > spam_cropped.txt # # #!/usr/bin/env python import sys f_rndtxt = open('../text/rndtxt.txt') f_spam_image = open('../text/spam_cropped.txt') rndtxt = f_rndtxt.read() rndtxt_index = 0 swap = 1 spam_image_text = f_spam_image.read() print """ RNDTXT """ while rndtxt_index < len(rndtxt): swap = 1 - swap if swap: background = '#334466' foreground = '#CCDDFF' else: background = '#CCDDFF' foreground = '#334466' print """
""" % (background, foreground),

    for letter in spam_image_text:
        if letter == ' ':
            sys.stdout.write(' ')
        elif letter == '\n':
            sys.stdout.write("\n")
        else:
            while rndtxt_index < len(rndtxt) and (rndtxt[rndtxt_index] == ' ' or rndtxt[rndtxt_index] == "\n"):
                rndtxt_index += 1

            if rndtxt_index < len(rndtxt):
                sys.stdout.write(rndtxt[rndtxt_index])
            rndtxt_index += 1
    print "
" f_rndtxt.close() f_spam_image.close() print """ """ # # # End References [1] http://mathworld.wolfram.com/ChaosGame.html [2] http://mathworld.wolfram.com/EulerProduct.html [3] http://mathworld.wolfram.com/RiemannZetaFunction.html [4] http://freetts.sf.net [5] http://www.plogue.com/bidule/ [6] http://noise.me.uk/montagestudies